using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Security.Principal;
using System.Threading;
using System.Web.ClientServices;
using System.Windows;
using System.Windows.Media;
using System.Collections.Generic;
using System.Text;

using System.Windows.Controls;

namespace Microsoft.PowerShell.CmdletManagement
{
    internal static class CmdletDesignerUtils
    {
        internal static void HandleException(string title, string context, Exception exc)
        {
            if (String.IsNullOrEmpty(title))
            {
                title = "Error";
            }

            if (String.IsNullOrEmpty(context))
            {
                context = "Could not execute command.";
            }

            string message = context;
            if (exc != null)
            {
                message += "\n\n" + exc.Message;
            }
            message += "\n\n" + "Please see http://psstudio.codeplex.com for additional details.";
            
            MessageBox.Show(message, title);
        }
    
        internal static void ResizeColumns(ListView listView, string fillColumn)
        {
            if (listView == null)
                return;

            GridView gridView = listView.View as GridView;

            if ((gridView != null) && (listView.ActualWidth > 0))
            {
                double availableWidth = listView.ActualWidth;
                int fillIndex = -1;

                for (int columnIndex = 0; columnIndex < gridView.Columns.Count; columnIndex++)
                {
                    GridViewColumn column = gridView.Columns[columnIndex];

                    string header = column.Header as String;
                    if(header == null)
                        header = ((GridViewColumnHeader)column.Header).Content as String;

                    if (header != fillColumn)
                    {
                        column.Width = column.ActualWidth;
                        column.Width = Double.NaN;
                        availableWidth -= column.ActualWidth;
                    }
                    else
                    {
                        fillIndex = columnIndex;
                    }
                }

                // Adjustment for margins
                availableWidth -= 6;

                if ((fillIndex != -1) && (availableWidth > 0))
                {
                    gridView.Columns[fillIndex].Width = availableWidth;
                }
            }
        }

        internal static bool DoesSearchMatchCmdlet(PsSpecCmdlet cmdlet, string searchText)
        {
            string cmdletName = cmdlet.Verb + "-" + cmdlet.Noun;

            // Trimmed search and combinedCmdletName let users find the Get-Foo
            // cmdlet by typing:
            // "GetFoo" and "Get Foo"
            string trimmedSearch = searchText.Replace(" ", "");
            trimmedSearch = trimmedSearch.Replace("-", "");
            string combinedCmdletName = cmdletName.Replace("-", "");

            if (
                (String.IsNullOrEmpty(searchText)) ||
                (searchText == "Search") ||
                (cmdletName.IndexOf(searchText, StringComparison.InvariantCultureIgnoreCase) >= 0) ||
                (combinedCmdletName.IndexOf(trimmedSearch, StringComparison.InvariantCultureIgnoreCase) >= 0)
                )
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        internal static bool DoesSearchMatchProject(PsSpecProject project, string searchText)
        {
            string projectName = project.Name;

            // Trimmed search and combinedProjectName let users find the PowerShell-Foo
            // project by typing:
            // "PowerShellFoo" and "PowerShell Foo"
            string trimmedSearch = searchText.Replace(" ", "");
            trimmedSearch = trimmedSearch.Replace("-", "");
            string combinedProjectName = projectName.Replace("-", "");

            if (
                (String.IsNullOrEmpty(searchText)) ||
                (searchText == "Search") ||
                (projectName.IndexOf(searchText, StringComparison.InvariantCultureIgnoreCase) >= 0) ||
                (combinedProjectName.IndexOf(trimmedSearch, StringComparison.InvariantCultureIgnoreCase) >= 0)
                )
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        internal static bool IsInRole(PsSpecProjectRole role, Application application)
        {
            if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                return true;
            }

            switch (role)
            {
                case PsSpecProjectRole.ProjectOwner: return (bool)application.Properties["IsProjectOwner"];
                case PsSpecProjectRole.SpecWriter: return (bool)application.Properties["IsSpecWriter"];
                case PsSpecProjectRole.HelpWriter: return (bool)application.Properties["IsHelpWriter"];
            }

            return false;
        }

        internal static void DisableAllCustomControls(FrameworkElement current)
        {
            ExtendedTextBlock extendedTextBlock = current as ExtendedTextBlock;
            if (extendedTextBlock != null)
            {
                extendedTextBlock.IsReadOnly = true;
            }

            FreeTextExtendedTextBlock freeTextExtendedTextBlock = current as FreeTextExtendedTextBlock;
            if (freeTextExtendedTextBlock != null)
            {
                freeTextExtendedTextBlock.IsReadOnly = true;
            }

            ExtendedCheckBox extendedCheckBox = current as ExtendedCheckBox;
            if (extendedCheckBox != null)
            {
                extendedCheckBox.IsReadOnly = true;
            }

            ExtendedListBox extendedListBox = current as ExtendedListBox;
            if (extendedListBox != null)
            {
                extendedListBox.IsReadOnly = true;
            }

            ParameterSetGroupingEditor parameterSetGroupingEditor = current as ParameterSetGroupingEditor;
            if (parameterSetGroupingEditor != null)
            {
                parameterSetGroupingEditor.IsReadOnly = true;
            }

            SpecExamplesControl specExamples = current as SpecExamplesControl;
            if (specExamples != null)
            {
                specExamples.HelpExamplesPanel.IsEnabled = false;
            }

            foreach (FrameworkElement child in EnumerateAllControls(current))
            {
                DisableAllCustomControls(child);
            }
        }

        //// Find a child of the markup for an item
        //internal static childItem FindVisualChild<childItem>(DependencyObject obj)
        //    where childItem : DependencyObject
        //{
        //    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        //    {
        //        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        //        if (child != null && child is childItem)
        //            return (childItem)child;
        //        else
        //        {
        //            childItem childOfChild = FindVisualChild(child);
        //            if (childOfChild != null)
        //                return childOfChild;
        //        }
        //    }

        //    return null;
        //}

        private static object GetChildHelper(ListView listView, ListViewItem lvItem, string name)
        {
            Border border = VisualTreeHelper.GetChild(lvItem, 0) as Border;
            ContentPresenter contentPresenter = VisualTreeHelper.GetChild(border, 0) as ContentPresenter;
            return listView.ItemTemplate.FindName(name, contentPresenter);
        }

        private static IEnumerable<FrameworkElement> EnumerateAllControls(FrameworkElement parentControl)
        {
            foreach (Object child in LogicalTreeHelper.GetChildren(parentControl))
            {
                FrameworkElement childFrameworkElement = child as FrameworkElement;
                if (childFrameworkElement != null)
                {
                    yield return childFrameworkElement;

                    foreach (FrameworkElement grandChild in EnumerateAllControls(childFrameworkElement))
                        yield return grandChild;
                }
            }
        }

        internal static bool TryGetIdentity(out IIdentity identity)
        {
            ClientRolePrincipal principal = Thread.CurrentPrincipal as ClientRolePrincipal;

            if (principal != null)
            {
                identity = principal.Identity;
                return true;
            }
            identity = null;

            return false;
        }

        internal static void EnsureCmdletDesignerModule(Runspace runspace, Window window)
        {
            // dump some diagnostics information
            using (Pipeline pipeline = runspace.CreatePipeline())
            {
                pipeline.Commands.AddScript(@"Get-ChildItem env: | Select Name, Value | ConvertTo-HTML | Out-File .\Environment.htm");
                pipeline.Invoke();
            }

            // always recreate commanddesigner module (blergh)
            // todo: version module along with application.
            CreateCmdletDesignerModule(runspace);

            // Load the PsSpecCmdlets.dll module
            using (Pipeline pipeline = runspace.CreatePipeline())
            {
                Command command = new Command("Import-Module");
                command.Parameters.Add("Name", @"CommandDesigner");
                pipeline.Commands.Add(command);

                string errors = "";

                try
                {
                    Collection<PSObject> results = pipeline.Invoke();
                }
                catch (Exception e)
                {
                    errors += e.Message;
                }

                if (pipeline.Error.Count > 0)
                {

                    foreach (PSObject error in pipeline.Error.ReadToEnd())
                    {
                        errors += error.ToString();
                    }
                }

                if (!String.IsNullOrEmpty(errors))
                {
                    errors += "\n\nPlease see http://psstudio.codeplex.com for further assistance.";

                    MessageTextBox messageTextBox = new MessageTextBox(window);
                    messageTextBox.Title = "Errors importing a module.";
                    messageTextBox.Text = "Errors importing the .\\PsSpecCmdlets.dll module.\n\n" + errors;
                    messageTextBox.ShowDialog();
                }
            }
        }


        internal static void CreateCmdletDesignerModule(Runspace runspace)
        {
            // ReSharper disable PossibleNullReferenceException
            string processFile = Process.GetCurrentProcess().MainModule.FileName;
            // ReSharper restore PossibleNullReferenceException

            string directoryName = Path.GetDirectoryName(processFile);

            string manifest = @"
#
# Module manifest for module 'CommandDesigner'
#
# Generated by: PowerShell Studio
#
# Generated on: 1/28/2010
#
 
@{
 
# Script module or binary module file associated with this manifest
ModuleToProcess = 'CommandDesigner.psm1'
 
# Version number of this module.
ModuleVersion = '1.0'
 
# ID used to uniquely identify this module
GUID = '0ad80a05-96c8-43cb-914e-beefbeefbeef'
 
# Author of this module
Author = 'Oisin Grehan'
 
# Company or vendor of this module
CompanyName = 'PowerShell Studio'
 
# Copyright statement for this module
Copyright = '2010'
 
# Description of the functionality provided by this module
Description = 'Cmdlets to communicate with the Command Designer database'
 
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = ''
 
# Name of the Windows PowerShell host required by this module
PowerShellHostName = ''
 
# Minimum version of the Windows PowerShell host required by this module
PowerShellHostVersion = ''
 
# Minimum version of the .NET Framework required by this module
DotNetFrameworkVersion = ''
 
# Minimum version of the common language runtime (CLR) required by this module
CLRVersion = ''
 
# Processor architecture (None, X86, Amd64, IA64) required by this module
ProcessorArchitecture = ''
 
# Modules that must be imported into the global environment prior to importing this module
RequiredModules = @()
 
# Assemblies that must be loaded prior to importing this module
RequiredAssemblies = @()
 
# Script files (.ps1) that are run in the caller's environment prior to importing this module
ScriptsToProcess = @()
 
# Type files (.ps1xml) to be loaded when importing this module
TypesToProcess = @()
 
# Format files (.ps1xml) to be loaded when importing this module
FormatsToProcess = @()
 
# Modules to import as nested modules of the module specified in ModuleToProcess
NestedModules = @()
 
# Functions to export from this module
FunctionsToExport = '*'
 
# Cmdlets to export from this module
CmdletsToExport = '*'
 
# Variables to export from this module
VariablesToExport = '*'
 
# Aliases to export from this module
AliasesToExport = '*'
 
# List of all modules packaged with this module
ModuleList = @()
 
# List of all files packaged with this module
FileList = @()
 
# Private data to pass to the module specified in ModuleToProcess
PrivateData = ''
 
}
";

            string script = @"
param([string]$path, [string]$manifest)
$psScriptRoot= ""$home\Documents\WindowsPowerShell\Modules\CommandDesigner""
New-Item $psScriptRoot -type Directory -Force  | Out-Null
[IO.File]::WriteAllText(""$psScriptRoot\CommandDesigner.psd1"", $manifest)
$modulePath = ""$psScriptRoot\CommandDesigner.psm1""
if ((Test-Path $modulePath -ErrorAction SilentlyContinue)) {
    $oldLines = Get-Content $modulePath
    $newLines = New-Object Text.StringBuilder
    foreach ($line in $oldLines) {
        if ($line -notlike 'Import-Module ''*\PsSpecCmdlets.dll''') {
            $null = $newLines.Append($line)
            $null = $newLines.Append([Environment]::NewLine)
        } else {
            $null = $newLines.Append(""Import-Module '$path\PsSpecCmdlets.dll'"")
            $null = $newLines.Append([Environment]::NewLine)
        }
    }
    [IO.File]::WriteAllText($modulePath, $newLines)        
} else {
    [IO.File]::WriteAllText($modulePath, ""Import-Module '$path\PsSpecCmdlets.dll'"")
}
$Culture = Get-Culture
New-Item ""$psScriptRoot\$culture"" -type Directory -Force  | Out-Null
 
Get-ChildItem $Path -Filter '*-Help.xml' -ErrorAction SilentlyContinue |
    Copy-Item -Destination ""$psScriptRoot\$culture\"" -Force | 
    Out-Null
 
";
            System.Management.Automation.PowerShell psCmd = System.Management.Automation.PowerShell.Create();
            psCmd.Runspace = runspace;
            Collection<PSObject> result = psCmd
                .AddScript(script)
                .AddParameter("Path", directoryName)
                .AddParameter("Manifest", manifest)
                .Invoke();
        }
    }
}
